<?php

class fwController {

    /**
     * Содержит имя метода в классе контроллера
     * @var string
     */
    private $action = "index";
    /**
     * Содержит аргументы запроса
     * @var array
     */
    private $arguments = array();
    /**
     * Содержит экземпляр класса контроллера
     * @var object
     */
    private $controller;
    /**
     * Путь к директории контроллеров, относительно директории "app"
     * @var string
     */
    private $controller_dir = "controller";
    /**
     * Короткое имя контроллера. Совпадает с именем файла (без расширения).
     */
    private $controller_name;
    /**
     * Путь к директории представлений, относительно директории "app"
     * @var string
     */
    private $view_dir = "view";
    /**
     * Содержит экземпляр render
     */
    private $render;


    function __construct() {
        $this->findArguments();
        $this->findController();
        $this->findAction();
    }

    /**
     * Запуск фронт контроллера, используется одинажды.
     * @return void
     */
    public function run() {
        if (count($this->getArguments()) > 1) {
            $data = call_user_func_array(array($this->getController(), $this->getAction()), array($this->getArguments()));
        } elseif (count($this->getArguments() == 1)) {
            $data = call_user_func(array($this->getController(), $this->getAction()), array_shift($this->getArguments()));
        } else {
            $data = call_user_func(array($this->getController(), $this->getAction()), array(""));
        }
        if ($this->hasArgument("ajax")) {
            $this->render = new fwRenderAjax();
        } elseif ($this->hasArgument("print")) {
            $this->render = new fwRenderPrint();
        } else {
            $this->render = new fwRenderLayout();
        }
        echo $this->render->publish($data);
    }

    /**
     * Получить названия исполняемого метода в контроллере
     * @return string
     */
    public function getAction() {
        return $this->action;
    }

    /**
     * Получить массив аргументов запроса.
     * @return array
     */
    public function getArguments() {
        return $this->arguments;
    }

    /**
     * Получить экземпляр класса контроллера
     */
    public function getController() {
        return $this->controller;
    }

    /**
     * Получить короткое имя контроллера. (совпадает с именем файла).
     */
    public function getControllerName() {
        return $this->controller_name;
    }

    /**
     * Получить имя класса контроллера.
     * @return string 
     */
    public function getControllerClassName() {
        return get_class($this->controller);
    }

    /**
     * Получить полный путь к директории контроллера
     */
    public function getControllerDir() {
        return APP . $this->controller_dir . DS;
    }

    /**
     * Получить полный путь к директории представления
     */
    public function getViewDir() {
        return APP . $this->view_dir . DS;
    }

    /**
     * Проверка наличия аргумента в запросе.
     * @param string $arg 
     * @return boolean
     */
    public function hasArgument($arg) {
        return in_array($arg, $this->arguments);
    }

    /**
     * Изменить путь к контроллерам проекта относительно application директории. По умолчанию: "controller"
     * (Если указанный путь не будет найден, то будет использоваться путь по умолчанию.)
     * @param string $path
     * @example path/to/controller
     */
    public function setControllerDir($dir) {
        $a1 = explode("\\", $dir);
        $a2 = explode("/", $dir);
        if (count($a1) > count($a2)) {
            $dir = implode(DS, $a1);
        } else {
            $dir = implode(DS, $a2);
        }
        $path = APP . $dir . DS;
        if (file_exists($path) && is_dir($path)) {
            $this->controller_dir = $dir;
        }
    }

    /**
     * Изменить путь к представлениям проекта относительно application директории. По умолчанию: "view" 
     * (Если указанный путь не будет найден, то будет использоваться путь по умолчанию.)
     * @param string $path 
     * @example path/to/view
     */
    public function setViewDir($dir) {
        $a1 = explode("\\", $dir);
        $a2 = explode("/", $dir);
        if (count($a1) > count($a2)) {
            $dir = implode(DS, $a1);
        } else {
            $dir = implode(DS, $a2);
        }
        $path = APP . $dir . DS;
        if (file_exists($path) && is_dir($path)) {
            $this->view_dir = $dir;
        }
    }

    private function findArguments() {
        if (count($_GET)) {
            $query = explode("/", $_GET["q"]);
            foreach ($query as $s) {
                if (S::validator()->isLatAlphaNumeric($s)) {
                    $this->arguments[] = $s;
                }
            }
        }
    }

    private function findController() {
        $class = "app";
        $a = explode(DS, $this->controller_dir);
        foreach ($a as $d) {
            $class.=ucfirst(strtolower($d));
        }
        $path = $this->getControllerDir();

        $use_default = true;
        $args = $this->getArguments();
        if (count($args)) {
            foreach ($args as $arg) {
                $class.=ucfirst(strtolower($arg));
                if (class_exists($class)) {
                    $this->arguments = $args;
                    $this->controller_name = strtolower($arg);
                    $use_default = false;
                    break;
                }
            }
        }
        if ($use_default) {
            $cda = explode(DS, $this->controller_dir);
            $class = "app";
            foreach ($cda as $cd) {
                $class.=ucfirst(strtolower($cd));
            }
            $class.="Default";
            $this->controller_name = "default";
        }
        $this->controller = new $class();
    }

    private function findAction() {
        if (count($this->getArguments())) {
            $test = array_shift($this->getArguments());
            if (S::validator()->isLatAlphaNumeric($test) && method_exists($this->getController(), $test)) {
                $this->action = array_shift($this->arguments);
            } else {
                $this->action = "index";
            }
        }
    }

}

?>
